package org.sunspotworld;

import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.peripheral.IAccelerometer3D;
import com.sun.spot.io.j2me.radiogram.*;
import com.sun.spot.sensorboard.io.IScalarInput;
import com.sun.spot.sensorboard.peripheral.ISwitch;
import com.sun.spot.util.*;

import java.io.*;
import javax.microedition.io.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

/**
 * The startApp method of this class is called by the VM to start the
 * application.
 *
 * The manifest specifies this class as MIDlet-1, which means it will
 * be selected for execution.
 */
public class SunSpotGloveRemoteApp extends MIDlet {

    private static final int HOST_PORT = 100;
    private static final int SAMPLE_FREQUENCY = 50;  /* in milliseconds */

    private static final int ANTIALIASING = 4;     /* How many actual samples there are per one averaged sent sample. 1 means no antialiasing. */

    private static final boolean CONNECT_ONCE = false;  /* Wheather to use one constant connection for the whole communication. */

    /*********************************/
    private RadiogramConnection conn;
    private Datagram dg;
    private IAccelerometer3D accel;
    private ISwitch sw1;
    private IScalarInput[] analogInputs;

    /*********************************/
    public SunSpotGloveRemoteApp() {
        this.accel = EDemoBoard.getInstance().getAccelerometer();
        this.sw1 = EDemoBoard.getInstance().getSwitches()[0];
        this.analogInputs = EDemoBoard.getInstance().getScalarInputs();
        EDemoBoard.getInstance().getOutputPins()[0].setHigh();
        EDemoBoard.getInstance().getOutputPins()[1].setHigh();
    }

    /* Start midlet */
    protected void startApp() throws MIDletStateChangeException {
        new BootloaderListener().start();   // monitor the USB (if connected) and recognize commands from host

        String ourAddress = System.getProperty("IEEE_ADDRESS");
        System.out.println("Remote radio address = " + ourAddress);

        try {
            accel.setRestOffsets();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        startAcceWatchThreadd();
    }

    public void startAcceWatchThreadd() {

        new Thread() {

            public void run() {
                try {
                    if (CONNECT_ONCE) {
                        conn = (RadiogramConnection) Connector.open("radiogram://broadcast:" + HOST_PORT);
                        dg = conn.newDatagram(conn.getMaximumLength());
                    }

                    while (true) {

                        long time = System.currentTimeMillis();

                        String msg = checkingAntialiasedMovements();

                        if (msg != null) {
                            sendOut(msg);
                        }

                        try {
                            long sleep = Math.max(0, (1000 / (ANTIALIASING * SAMPLE_FREQUENCY) - (System.currentTimeMillis() - time)));
                            Thread.sleep(sleep);
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }.start();
    }


    /* Performs ANTIALIASING number of samples at ANTIALIASING*SAMPLE_FREQUENCY frequency and returns an average of the measured values*/
    private String checkingAntialiasedMovements() {

        if (ANTIALIASING <= 0) {
            return null;
        }

        double[][] aliasingTable = new double[ANTIALIASING - 1][7];
        String msg = null;

        try {
            for (int i = 0; i < ANTIALIASING - 1; i++) {

                long time = System.currentTimeMillis();

                aliasingTable[i][0] = accel.getRelativeAccelX();
                aliasingTable[i][1] = accel.getRelativeAccelY();
                aliasingTable[i][2] = accel.getRelativeAccelZ();
                aliasingTable[i][3] = analogInputs[0].getValue();
                aliasingTable[i][4] = analogInputs[1].getValue();
                aliasingTable[i][5] = analogInputs[2].getValue();
                aliasingTable[i][6] = analogInputs[3].getValue();

                try {
                    long sleep = Math.max(0, (1000 / (ANTIALIASING * SAMPLE_FREQUENCY) - (System.currentTimeMillis() - time)));
                    Thread.sleep(sleep);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }

            double xAccel = accel.getRelativeAccelX();
            double yAccel = accel.getRelativeAccelY();
            double zAccel = accel.getRelativeAccelZ();
            double a0 = analogInputs[0].getValue();
            double a1 = analogInputs[1].getValue();
            double a2 = analogInputs[2].getValue();
            double a3 = analogInputs[3].getValue();

            for (int i = 0; i < ANTIALIASING - 1; i++) {
                xAccel += aliasingTable[i][0];
                yAccel += aliasingTable[i][1];
                zAccel += aliasingTable[i][2];
                a0 += aliasingTable[i][3];
                a1 += aliasingTable[i][4];
                a2 += aliasingTable[i][5];
                a3 += aliasingTable[i][6];
            }
            xAccel /= ANTIALIASING;
            yAccel /= ANTIALIASING;
            zAccel /= ANTIALIASING;
            a0 /= ANTIALIASING;
            a1 /= ANTIALIASING;
            a2 /= ANTIALIASING;
            a3 /= ANTIALIASING;

            msg = sw1.isClosed() + ";" + xAccel + ";" + yAccel + ";" + zAccel + ";" + a0 + ";" + a1 + ";" + a2 + ";" + a3;
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        return msg;
    }

    private synchronized void sendOut(String msg) {

        try {
            if (!CONNECT_ONCE) {
                conn = (RadiogramConnection) Connector.open("radiogram://broadcast:" + HOST_PORT);
                dg = conn.newDatagram(conn.getMaximumLength());
            }

            try {
                dg.writeUTF(msg);
                conn.send(dg);
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (!CONNECT_ONCE) {
                conn.close();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    protected void pauseApp() {
        // This will never be called by the Squawk VM
    }

    protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
        // Only called if startApp throws any exception other than MIDletStateChangeException
    }
}
